<?php

namespace App\Http\Controllers\Api\Orders;

use App\Exceptions\TrainOrderDeletedException;
use App\Http\Controllers\Controller;
use App\Http\Requests\Train\Order\RequiredOrderSnRequest;
use App\Http\Resources\Task\TrainSnapTaskInfoResource;
use App\Http\Resources\Train\Snap\SnapSeatsResource;
use App\Http\Resources\Train\TrainOrder\PriceDetailsResource;
use App\Http\Resources\Train\TrainOrder\TrainOrderPassengerResource;
use App\Http\Resources\Train\TrainOrder\TrainOrderRefundResource;
use App\Http\Resources\Train\TrainOrder\TrainOrderResource;
use App\Http\Resources\Trip\Orders\PassengerCostResource;
use App\Http\Resources\Trip\Orders\PassengerRefundsResource;
use App\Http\Resources\Trip\Orders\TransferResource;
use App\Models\Orders\Repositories\Interfaces\OrdersRepositoryInterface;
use App\Models\Task\SnapTasks\Repositories\Interfaces\SnapTaskRepositoryInterface;
use App\Models\Train\Stations\Repositories\Interfaces\StationRepositoryInterface;
use App\Models\Train\TrainOrderPassengers\Repositories\Interfaces\TrainOrderPassengersRepositoryInterface;
use App\Models\Train\TrainOrderPassengers\TrainOrderPassenger;
use App\Models\Train\TrainOrders\Repositories\Interfaces\TrainOrdersRepositoryInterface;
use App\Models\Train\TrainPoints\Repositories\Interfaces\TrainPointsRepositoryInterface;
use App\Models\Trip\TripOrderRefund\TripOrderRefund;
use App\Trip\Orders\BookOrders\BookOrdersManager;
use App\Trip\Orders\BookOrders\SnapUp\SnapUpData;
use App\Trip\Passengers\OrderSubPassenger;
use App\Trip\Train\Order\Impl\PiaoChiOrderPassengerRefundImpl;
use App\Trip\Train\Providers\Ctrip\TrainQuery;
use Carbon\Carbon;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Log;
use Throwable;

class TrainOrdersController extends Controller
{

    private TrainPointsRepositoryInterface          $trainPointRepo;
    private StationRepositoryInterface              $stationRepo;
    private TrainOrdersRepositoryInterface          $trainOrderRepo;
    private OrdersRepositoryInterface               $orderRepo;
    private TrainOrderPassengersRepositoryInterface $orderPassengerRepo;
    private string|null                             $user_id;
    private SnapTaskRepositoryInterface             $snapTaskRepository;

    public function __construct(
        TrainPointsRepositoryInterface          $trainPointsRepository,
        StationRepositoryInterface              $stationRepository,
        TrainOrdersRepositoryInterface          $trainOrdersRepository,
        OrdersRepositoryInterface               $commonOrderRepository,
        SnapTaskRepositoryInterface             $snapTaskRepository,
        TrainOrderPassengersRepositoryInterface $orderPassengersRepository
    )
    {
        $this->trainPointRepo     = $trainPointsRepository;
        $this->stationRepo        = $stationRepository;
        $this->trainOrderRepo     = $trainOrdersRepository;
        $this->orderRepo          = $commonOrderRepository;
        $this->orderPassengerRepo = $orderPassengersRepository;
        $this->snapTaskRepository = $snapTaskRepository;
        $this->user_id            = auth()->id();
    }

    public function train_orders(Request $request)
    {
        $params            = $request->only([
            'sort_key',
            'sort_value',
            'is_valid',
        ]);
        $params['user_id'] = $this->user_id;
//        Log::info(json_encode(['method' => '火车票订单列表', 'request' => $request->all()], JSON_UNESCAPED_UNICODE));
        $res = $this->trainOrderRepo->lists($params, $request->input('page_size', 5));


        $request->offsetSet('business', 'train_order_list');
        $res['orders'] = TrainOrderResource::collection($res['orders']);
        return $this->success('', $res);
    }

    public function order_info(RequiredOrderSnRequest $request)
    {

        $user_id   = $this->user_id;
        $error_msg = "";
        try {
            $order_info = $this->trainOrderRepo->getOrderInfo($request->input('order_sn'));
        } catch (TrainOrderDeletedException $e) {
            if ($e->getOriginOrderSn()) {
                $order_info = $this->trainOrderRepo->getOrderInfo($e->getOriginOrderSn());
                $error_msg  = "当前订单已删除,已自动显示原订单";
            } else {
                $order_info = null;
            }
        }
        if (!$order_info || !Gate::allows('order-access', $order_info)) {
            return $this->error(404, "订单不存在");
        }
        $orderInfoData = $this->trainOrderRepo->getOrderShowInfoDatasByTrainOrder($order_info);
        return $this->success($error_msg, $orderInfoData);
    }

    /**
     * 火车票抢票
     *
     * @param Request $request
     *
     * @throws Exception
     */
    public function snap_up(Request $request)
    {
        $orderData            = $request->all();
        $orderData['user_id'] = $this->user_id;
        $order_manager        = new BookOrdersManager($orderData);
        $task_order           = $order_manager->snap_up();
        $task_info            = $task_order->snap_task_info();
        return $this->success("", ['task_info' => new TrainSnapTaskInfoResource($this->snapTaskRepository->getTaskShowInfo($task_info))]);

    }

    public function snap_before_data(Request $request)
    {
        $snap_data = new SnapUpData($request->all());
        return $this->success('success', [
            'snap_success_rate' => $snap_data->calcSnapSuccessRate(),
            'snap_levels'       => $snap_data->getChooseSnapLevels(),
            'select_seats'      => $snap_data->getSelectSeatsByAlternativeSeats(),
            'stop_times'        => $snap_data->getStopTimes(),
        ]);
    }

    public function snap_dates(Request $request)
    {
        $snap_data = new SnapUpData([]);
        $dates     = $snap_data->getDates($request->input('train_date', Carbon::now()->toDateString()));
        return $this->success('success', $dates);
    }

    public function snap_seats(Request $request)
    {
        $snap_data     = new SnapUpData([]);
        $data          = $snap_data->getSnapAllSeats($request->all());
        $data['seats'] = SnapSeatsResource::collection($data['seats']);
        return $this->success('success', $data);
    }


    /**
     * 中转订单详情
     *
     * @param RequiredOrderSnRequest $request
     *
     */
    public function transfer(RequiredOrderSnRequest $request)
    {
        $order_info = $this->orderRepo->getOrderInfo($request->input('order_sn'));
        if (!$order_info || !Gate::allows('order-access', $order_info)) {
            return $this->error(404, "订单不存在");
        }
        $transfer               = $this->orderRepo->getTransferInfo($order_info);
        $transfer['order_info'] = new TransferResource($transfer['order_info']);
        return $this->success('', $transfer);
    }

    /**
     * 取消订单
     *
     * @param RequiredOrderSnRequest $request
     *
     */
    public function cancel(RequiredOrderSnRequest $request)
    {
        $order_info = $this->trainOrderRepo->getOrderInfo($request->input('order_sn'));
        if (!$order_info || !Gate::allows('order-access', $order_info)) {
            return $this->error(404, "订单不存在");
        }
        Log::info(json_encode(['method' => '取消订单', 'request' => $request->all()], JSON_UNESCAPED_UNICODE));
        $res = $this->trainOrderRepo->cancelOrder($order_info, $manual = true);
        if ($res) {
            return $this->success("success");
        }
        return $this->error(1, "出票结果确认中，暂无法取消，请稍后");

    }

    public function delete(RequiredOrderSnRequest $request)
    {
        $order_info = $this->orderRepo->getOrderInfo($request->input('order_sn'));
        if (!$order_info || !Gate::allows('order-access', $order_info)) {
            return $this->error(404, "订单不存在");
        }
        $this->orderRepo->destroy($order_info);

        return $this->success("success");

    }

    /**
     * 火车票改签
     *
     * @throws Exception|GuzzleException|Throwable
     */
    public function change(Request $request)
    {
        $orderData            = $request->all();
        $orderData['user_id'] = $this->user_id;
        $order_manager        = new BookOrdersManager($orderData);
        $orders               = $order_manager->train_change();
        Log::info(json_encode(['method' => '改签', 'request' => $request->all()], JSON_UNESCAPED_UNICODE));
        $order_info        = new TrainOrderResource($this->trainOrderRepo->getOrderShowInfo($orders['order_info']->getOrderSn()));
        $origin_order_info = new TrainOrderResource($this->trainOrderRepo->getOrderShowInfo($orders['origin_order_info']->getOrderSn()));
        $request->offsetSet('show_tip', 0);
        $price_details = new PriceDetailsResource($orders['price_details']);
        return $this->success('', compact('order_info', 'origin_order_info', 'price_details'));
    }

    /**
     * 改签钱价格计算
     *
     * @param Request $request
     *
     * @return Application|ResponseFactory|Response
     * @throws GuzzleException
     */
    public function before_change_price_details(Request $request)
    {
        $orderData            = $request->all();
        $orderData['user_id'] = $this->user_id;
        $order_manager        = new BookOrdersManager($orderData);
        $data                 = $order_manager->build_train_change_data($only_query_price = true);
        $price_details        = new PriceDetailsResource($data['price_details']);
        Log::info(json_encode(['method' => '改签钱价格计算', 'request' => $request->all()], JSON_UNESCAPED_UNICODE));
        return $this->success('', compact('price_details'));
    }

    public function order_passengers(RequiredOrderSnRequest $request)
    {
        // 标识改签乘客列表 过滤不必要的字段
        $request->offsetSet('change_passenger', 1);
        $order_info = $this->trainOrderRepo->getOrderInfo($request->input('order_sn'));
        if (!$order_info || !Gate::allows('order-access', $order_info)) {
            return $this->error(404, "订单不存在");
        }
        // 全部乘客 可改签的乘客 购票成功的才行
        Log::info(json_encode(['method' => '订单可改签的乘客', 'request' => $request->all()], JSON_UNESCAPED_UNICODE));
        $can_change_passengers = $order_info->getCanChangePassengers();
        $passengers            = TrainOrderPassengerResource::collection($can_change_passengers);
        Log::info(collect($passengers)->toJson(JSON_UNESCAPED_UNICODE));
        return $this->success('', compact('passengers'));
    }

    /**
     * @throws Exception
     */
    public function refund(RequiredOrderSnRequest $request)
    {
        $order_info = $this->trainOrderRepo->getOrderInfo($request->input('order_sn', ''));
        if (!$order_info || !Gate::allows('order-access', $order_info)) {
            return $this->error(404, "订单不存在");
        }
        /**
         * @var TrainOrderPassenger $passenger
         */
        $input_passenger_id = $request->input('passenger_id');
        $parsePassenger     = OrderSubPassenger::parsePassengerId($input_passenger_id);
        $passenger          = $order_info->getPassengerBy([
            "passenger_id" => $parsePassenger['passenger_id'],
            "sequence"     => $parsePassenger['sequence'],
        ]);
        /**
         * @var TripOrderRefund $refund_info
         */
        Log::info(json_encode(['method' => '订单发起退款', 'request' => $request->all()], JSON_UNESCAPED_UNICODE));
        $order_passenger_refund = new PiaoChiOrderPassengerRefundImpl($order_info, $passenger);
        if ($request->input('ignore_worktime_error', 0) == 1) {
            $order_passenger_refund->setIgnoreWorkTimeError();
        }
        $refund_info                          = $this->orderPassengerRepo->refund($order_passenger_refund);
        $refund_info['refund_amount_details'] = $refund_info->refund_amount_details();
        $refund_info                          = new TrainOrderRefundResource($refund_info);
        return $this->success('', $refund_info);
    }

    public function refund_info(RequiredOrderSnRequest $request)
    {
        $refund     = [];
        $order_info = $this->trainOrderRepo->getOrderInfo($request->input('order_sn'));
        if (!$order_info || !Gate::allows('order-access', $order_info)) {
            return $this->error(404, "订单不存在");
        }

        $has_origin              = (bool)$order_info->getOriginOrderSn();
        $refunds                 = $order_info->refunds();
        $originRefunds           = $has_origin ? $order_info->OriginOrderRefunds() : null;
        $originRefundAmount      = $originRefunds ? $refunds->sum('refund_amount') : 0;
        $refund['order_sn']      = $order_info->getOrderSn();
        $refund['refund_amount'] = $refunds->sum('refund_amount') + $originRefundAmount;
        $details                 = $order_info->refunds()->get();
        foreach ($details as $key => $detail) {
            $details[$key]['details'] = $detail->refund_amount_details();
        }
        $originRefundsDetails = [];
        if ($has_origin) {
            $originRefundsDetails = $order_info->OriginOrderRefunds()->get();
            foreach ($originRefundsDetails as $key => $detail) {
                $originRefundsDetails[$key]['details'] = $detail->refund_amount_details();
            }
            $originRefundsDetails = TrainOrderRefundResource::collection($originRefundsDetails);
        }
        $refund['details'] = TrainOrderRefundResource::collection($details);
        $refund['details'] = collect($refund['details'])->merge($originRefundsDetails);
        return $this->success('', compact('refund'));
    }

    /**
     * 退款前说明
     *
     * @throws Exception
     */
    public function before_refund_desc(RequiredOrderSnRequest $request)
    {
        $order_info = $this->trainOrderRepo->getOrderInfo($request->input('order_sn'));
        if (!$order_info || !Gate::allows('order-access', $order_info)) {
            return $this->error(404, "订单不存在");
        }

        $passenger = $order_info->getPassengerBy([
            "passenger_id" => $request->input('passenger_id'),
        ]);
        if (!$passenger) {
            return $this->error(404, "乘客不存在不存");
        }

        Log::info(json_encode(['method' => '订单退款前费用', 'request' => $request->all()], JSON_UNESCAPED_UNICODE));
        $ret = $passenger?->getBeforeRefund([
            'ignore_worktime_error' => 1,
        ]);
        if (!empty($ret['other_fee'])) {
            $ret['other_fee'] = PassengerCostResource::collection($ret['other_fee']);
        }

        if (!empty($ret['refunded_fee'])) {
            $ret['refunded_fee'] = PassengerRefundsResource::collection($ret['refunded_fee']);
        }
        return $this->success('', $ret);
    }

    /**
     * @throws GuzzleException
     */
    public function share_info(RequiredOrderSnRequest $request)
    {
        // 获取订单
        $order_info = $this->trainOrderRepo->getOrderShowInfo($request->input('order_sn'));
        if (!$order_info) {
            return $this->error(404, "订单不存在");
        }
        // 获取订单车次
        $train_code         = $order_info['train_code'];
        $from_station_code  = $order_info['from_station_code'];
        $to_station_code    = $order_info['to_station_code'];
        $train_date         = $order_info['train_date'];
        $order_info         = new TrainOrderResource($order_info);
        $list               = $this->trainPointRepo->listByTrainCode($train_code);
        $count              = $list->count();
        $isTrainDateFeature = Carbon::today()->lessThan($train_date);
        $isTrainDateExpired = Carbon::now()->greaterThan($train_date);
        if (!$isTrainDateFeature && !$isTrainDateExpired) {
            $query = new TrainQuery();
            try {
                $query->queryScreen($to_station_code, 1);
                $query->queryScreen($from_station_code, 0);
            } catch (Exception $e) {

            }
        }

        if ($count == 0) {
            // 从网络获取
            $query = new TrainQuery();
            $date  = $train_date;
            if ($isTrainDateFeature) {
                $date = Carbon::today()->toDateString();
            }
            $list = $query->queryStationPoints($train_code, $date);
        }

        // 获取候车|到达状态
        $passpoints = collect($list)
            ->map(function ($point, $idx) use ($from_station_code, $to_station_code, $count, $isTrainDateFeature, $isTrainDateExpired) {
                $ret     = $point;
                $is_from = $point['station_code'] == $from_station_code;
                $is_to   = $point['station_code'] == $to_station_code;
                if ($isTrainDateExpired) {
                    $trip_state = '--';
                } else if ($isTrainDateFeature) {
                    $trip_state = __('预计正点');
                } else {
                    $trip_state = ($is_from || $is_to);
                }

                $station                = $this->stationRepo->findOneByCode($point['station_code']);
                $ret['is_start']        = $point['sequence'] == 1 ? 1 : 0;
                $ret['is_from']         = $is_from ? 1 : 0;
                $ret['is_to']           = $is_to ? 1 : 0;
                $ret['is_end']          = $point['sequence'] == $count ? 1 : 0;
                $ret['station_name']    = $station?->getStationName();
                $ret['station_name_uy'] = $station?->getStationNameUy();
                $ret['trip_state']      = $trip_state;
                return $ret;
            })->toArray();


        return $this->success('success', compact('order_info', 'passpoints'));
    }


}
